Skip to main content

TCP Handshake

The TCP 3-way handshake is the process by which a client and server establish a reliable connection before exchanging data. It ensures that both sides are ready to communicate, sequence numbers are synchronized, and the network path is working.

Step-by-Step: TCP 3-Way Handshake

StepSender → ReceiverDescription
1️⃣ SYNClient → ServerClient sends a SYN (synchronize) packet with an initial sequence number (e.g., Seq = 100) to start a connection.
2️⃣ SYN-ACKServer → ClientServer replies with a SYN-ACK: acknowledges client's SYN and sends its own SYN with its own initial sequence number (e.g., Seq = 500, Ack = 101).
3️⃣ ACKClient → ServerClient sends back an ACK acknowledging the server’s SYN (Ack = 501). Connection is now established.

Purpose of TCP Handshake in System Design

  • Reliability: Ensures both ends are ready and capable of communication.
  • Sequence Number Sync: Sets up both sides to track packet order.
  • Avoids Half-Open Connections: Prevents unintentional connections caused by dropped packets or old messages.
  • Security (partial): Helps mitigate some basic spoofing or replay attacks by requiring return traffic.

Diagram of TCP Handshake

Client                                Server
| |
| ----------- SYN (Seq=100) --------> |
| |
| <------ SYN-ACK (Seq=500, Ack=101)--|
| |
| ------- ACK (Seq=101, Ack=501) ---->|
| |
Connection Established |

Example Scenario of TCP Handshake

Scenario: Web Client ↔ Web Server (HTTP over TCP) Let’s say a user visits a website (e.g., https://example.com):

  1. Browser initiates TCP connection to example.com on port 443.
  2. TCP 3-way handshake happens to establish a reliable connection.
  3. Once connected, HTTPS handshake begins, followed by HTTP request/response.

Without this TCP handshake, the HTTP request might go to a server that’s not ready, causing dropped data or errors.

TCP Handshake with Node.js

Although Node.js abstracts the actual handshake, here’s how the net module internally triggers it when connect() is called:

Server

const net = require("net");

const server = net.createServer((socket) => {
console.log("Client connected"); // after handshake
});

server.listen(3000, () => {
console.log("Server listening on port 3000");
});

Client

const net = require("net");

const client = net.createConnection({ port: 3000 }, () => {
console.log("Connected to server"); // handshake complete
});
  • When client.createConnection() is called:
    • OS sends SYN.
    • Waits for SYN-ACK.
    • Sends ACK.
  • Only after that will the "connect" callback fire.

TCP Handshake Use Cases

Use CaseHow TCP Handshake Helps
MicroservicesEnsures gRPC/HTTP clients don’t send data until backend is ready.
Load balancers (e.g., Nginx, HAProxy)Wait for successful handshake before forwarding requests.
API GatewaysEstablishes stable connection before passing request to backend service.
Database ClientsPostgreSQL or MySQL drivers use handshake before sending queries.

System Design Considerations of TCP Handshake

ChallengeExplanation
LatencyAdds round-trip time before data starts flowing.
Half-open connectionsClients that disconnect improperly can leave resources open on the server.
SYN flood attacksAttackers can send many SYNs without completing handshake, overwhelming the server (Mitigated via SYN cookies or rate limiting).